package com.hanggold.captcha.core.impl;

import com.hanggold.captcha.core.CaptchaAbstract;
import com.hanggold.captcha.execption.CaptchaException;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.OutputStream;

import static com.hanggold.captcha.util.RandomUtil.randomInt;

/**
 * 算术验证码.
 *
 * @author <a href="mailto:free@hanggold.com">free</a>
 * @date 2021-09-30 13:55
 * @since 1.0.0
 **/
@Slf4j
public class ArithmeticCaptcha extends CaptchaAbstract {
    
    public static final Integer[] CALCULATE_DIGIT = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    
    private static final String PLUS = "+";
    
    private static final String MINUS = "-";
    
    private static final String MULTI = "x";
    
    private static final String[] CALCULATE_STYLE = {PLUS, MINUS, MULTI};
    
    @Override
    public final char[] alphas() {
        int startDigit = CALCULATE_DIGIT[randomInt(CALCULATE_DIGIT.length)];
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(startDigit);
        String calculateStyle = CALCULATE_STYLE[randomInt(CALCULATE_STYLE.length)];
        switch (calculateStyle) {
            case PLUS:
                stringBuffer.append(PLUS);
                break;
            case MINUS:
                stringBuffer.append(MINUS);
                break;
            case MULTI:
                stringBuffer.append(MULTI);
                break;
            default:
                throw new CaptchaException("数字计算错误");
        }
        stringBuffer.append(CALCULATE_DIGIT[randomInt(CALCULATE_DIGIT.length)]);
        return stringBuffer.toString().toCharArray();
    }
    
    private String calculateValue(final String script) {
        String tempScript = script.replaceAll("x", "*");
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("javascript");
        try {
            return String.valueOf(engine.eval(tempScript));
        } catch (ScriptException e) {
            throw new CaptchaException(e);
        }
    }
    
    /**
     * 写入验证码.
     *
     * @param outputStream outputStream
     * @return string
     */
    @SneakyThrows
    @Override
    public String write(final OutputStream outputStream) {
        char[] targetCaptcha = alphas();
        String value = calculateValue(String.valueOf(targetCaptcha));
        final String standardWeightChar = standardWeightChar();
        buildImage(outputStream, standardWeightChar, weight(), height(), imageType(), (String.valueOf(targetCaptcha) + "=?").toCharArray());
        return value;
    }
    
}
